/*
 * Project: 2.4 GHz频段扫描仪
 * Author: Benik3(Dawn修改)
 * Created: 2018
 * License: None
 *
 * 注意：
 * 硬件为:| pro mini 开发板 | 0.96 i2c OLED 显示屏 | NRF24l01 模块
 * 注意 NRF24l01 供电为3V3，接5V必烧
 *
 * 原作者仓库：
 * https://github.com/Benik3/nRF24L01pScannerOled
 * 
 * 
 */
#include "SSD1X06.h"
#include "nrf.h"

/* 接线
  NRF24l01
   module   Arduino
   1 GND ---- GND
   2 VCC ---- 3.3V
   3 CE ----- D9
   4 CSN ---- D10
   5 SCK ---- D13 (SCK)
   6 MOSI --- D11 (MOSI)
   7 MISO --- D12 (MISO)
   8 IRQ ---- not connected

   OLED屏幕
   SCL --- A5
   SDA --- A4
*/

// 一共128个频道，每个相差1Mhz
#define CHANNELS 128

uint8_t MHz = 0;
uint16_t signalStrength[128];  // 平滑后的信号强度
uint8_t prevStrength[128];     // 当前信号强度
uint8_t column = 0;
uint16_t strength;
uint8_t row = 0;
uint8_t b = 0;
const uint8_t ff[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

void setup() {
  SSD1X06::start();
  delay(300);
  SSD1X06::fillDisplay(' ');

  nrf_init();
  NRF24L01_Reset();
  delay(150);

  NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00);     // 关闭 Shockburst 模式
  NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x0F);  // 设置默认值
  NRF24L01_SetTxRxMode(RX_EN);                    // 打开接收模式

  delay(100);

  for (int x = 0; x < 128; x++) {
    uint8_t b = 0x01;
    if (!(x % 10)) {
      b |= 0x06;
    }
    if (x == 10 || x == 60 || x == 110) {
      b |= 0xF8;
    }
    SSD1X06::displayByte(6, x, b);
  }
  SSD1X06::displayString6x8(7, 0, F("2.41"), 0);
  SSD1X06::displayString6x8(7, 50, F("2.46"), 0);
  SSD1X06::displayString6x8(7, 100, F("2.51"), 0);

  //配置定时器1
  cli();  //禁用所有中断
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;                            //计数值清零
  OCR1A = 45;                           //计数器溢出值 45 -> 6kHz
  TCCR1B |= (1 << WGM12);               // 打开CTC模式（Clear Timer on Compare Match） 当定时器的值与输出比较寄存器的值相等时，定时器会自动清零并产生一个中断
  TCCR1B |= (1 << CS11) | (1 << CS10);  // 设置预分频值为64
  TIMSK1 |= (1 << OCIE1A);              // 启用定时器1的输出比较A匹配中断。当定时器的值与OCR1A的值相匹配时，会触发一个中断

  NRF24L01_WriteReg(NRF24L01_05_RF_CH, MHz);
  CE_on;  // 开始接收
  sei();  // 允许中断
}

void loop() {
  draw_wave();
}

// 引脚初始化
void nrf_init() {
  pinMode(MOSI_pin, OUTPUT);
  pinMode(SCK_pin, OUTPUT);
  pinMode(CS_pin, OUTPUT);
  pinMode(CE_pin, OUTPUT);
  pinMode(MISO_pin, INPUT);
  CS_on;
  CE_on;
  MOSI_on;
  SCK_on;
  delay(70);
  CS_off;
  CE_off;
  MOSI_off;
  SCK_off;
  delay(100);
  CS_on;
  delay(10);
}

//绘制波形
void draw_wave() {

  strength = (signalStrength[column] + 0x0040) >> 7;
  if (strength > 48) {
    strength = 48;
  }

  uint8_t arr[6] = { 0 };

  if (strength > prevStrength[column]) {
    uint8_t val = strength - ((prevStrength[column] / 8) * 8);
    row = 6 - (strength / 8);
    if (strength % 8) row--;
    uint8_t nrow = ((val - 1) / 8);

    memcpy(arr, ff, nrow + 1);
    if (val % 8) {
      arr[0] = 0xFF << (8 - (val % 8));
    }

    SSD1X06::drawLine(row, column, nrow, arr);
    prevStrength[column] = strength;
  } else if (strength < prevStrength[column]) {
    row = 6 - (prevStrength[column] / 8);
    if (prevStrength[column] % 8) row--;
    uint8_t nrow = 5 - (strength / 8) - row;

    arr[nrow] = 0xFF << (8 - (strength % 8));
    SSD1X06::drawLine(row, column, nrow, arr);
    prevStrength[column] = strength;
  }

  column++;
  if (column == CHANNELS + 0) column = 0;
}

//中断程序
ISR(TIMER1_COMPA_vect) {  //定时器1产生中断就执行
  CE_off;
  if (NRF24L01_ReadReg(NRF24L01_09_CD)) {                        //如果接收到的信号功率大于-64 dBm 即有信号
    signalStrength[MHz] += (0x7FFF - signalStrength[MHz]) >> 5;  //则指数增加
  } else {                                                       //   >>5 即除以2的五次方即32 形成一个波动的效果
    signalStrength[MHz] -= signalStrength[MHz] >> 5;             //否则指数衰减
  }

  MHz++;
  if (MHz == CHANNELS + 0) MHz = 0;  //128个频道扫描完成，重新开始扫描

  NRF24L01_WriteReg(NRF24L01_05_RF_CH, MHz);  // 设置频率
  CE_on;                                      // 开始接收
  TCNT1 = 0;                                  // 清除计数器的值
  OCR1A = random(35, 55);                     // 溢出值搞成随机数，使波形显示效果更好，可以改成固定值试试看
}